/**
 * ReportGear(2011)
 */
package com.reportgear.report.print;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.abbp.core.utils.UnitUtils;
import net.abbp.report.model.Cell;
import net.abbp.report.model.ReportModel;
import net.abbp.report.model.cell.style.background.ColorBackground;
import net.abbp.report.model.headerfooter.ReportHF;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.reportgear.report.model.auxiliary.ColumnPropList;
import com.reportgear.report.model.auxiliary.ColumnType;
import com.reportgear.report.model.auxiliary.RowPropList;
import com.reportgear.report.setting.PaperSetting;
import com.reportgear.report.setting.ReportSettings;
import com.reportgear.report.view.grid.util.PaintUtils;

/**
 * 报表打印页
 * 
 * @version 1.0 2011-3-23
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class ReportPage implements Printable {
    private static final Logger logger = LoggerFactory.getLogger(ReportPage.class.getClass());
    // 当前页
    private int currentPageNumber;
    // 总页数
    private int totalPages;
    // 分组页
    private int groupPageNumber;
    // 分组总页数
    private int groupTotalPages;

    // 报表模型
    private final ReportModel reportModel;
    // 报表配置
    private final ReportSettings reportSettings;
    private final PaperSetting paperSetting;

    private final FT columnFT;
    private final RowFT rowFT;

    public ReportPage(ReportModel reportModel, RowFT rowFT, FT columnFT) {
        this.reportModel = reportModel;
        this.reportSettings = this.reportModel.getReportSettings();
        this.paperSetting = this.reportSettings.getPaperSetting();
        this.rowFT = rowFT;
        this.columnFT = columnFT;
    }

    /**
     * 
     * @return 页脚高度(inch)
     */
    public double getFooterHeight() {
        return this.reportSettings.getFooterHeight();
    }

    /**
     * 
     * @return 页眉高度(inch)
     */
    public double getHeaderHeight() {
        return this.reportSettings.getHeaderHeight();
    }

    /**
     * @return 下边距(inch)
     */
    public double getMarginBottom() {
        return this.paperSetting.getMargin().getBottom();
    }

    /**
     * @return 左边距(inch)
     */
    public double getMarginLeft() {
        return this.paperSetting.getMargin().getLeft();
    }

    /**
     * @return 右边距(inch)
     */
    public double getMarginRight() {
        return this.paperSetting.getMargin().getRight();
    }

    /**
     * @return 上边距(inch)
     */
    public double getMarginTop() {
        return this.paperSetting.getMargin().getTop();
    }

    /**
     * @return 页面方向
     */
    public int getOrientation() {
        return this.paperSetting.getOrientation();
    }

    /**
     * @return 页面高度(inch)
     */
    public double getPaperHeight() {
        PaperSize paperSize = this.paperSetting.getPaperSize();

        if (this.getOrientation() == PageFormat.PORTRAIT) {
            return Math.max(paperSize.getHeight(), paperSize.getWidth());
        } else {
            return Math.min(paperSize.getHeight(), paperSize.getWidth());
        }
    }

    /**
     * @return 页面宽度(inch)
     */
    public double getPaperWidth() {
        PaperSize paperSize = this.paperSetting.getPaperSize();

        if (this.getOrientation() == PageFormat.PORTRAIT) {
            return Math.min(paperSize.getHeight(), paperSize.getWidth());
        } else {
            return Math.max(paperSize.getHeight(), paperSize.getWidth());
        }
    }

    /**
     * 绘制报告页面
     * 
     * @param g 图形对象
     */
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        ColorBackground.getInstance(Color.WHITE)
                       .paint(g2,
                              new Rectangle2D.Double(0.0D,
                                                     0.0D,
                                                     UnitUtils.inch2pixel(this.getPaperWidth()),
                                                     UnitUtils.inch2pixel(this.getPaperHeight())));

        this.printPaint(g2, false);
    }

    // 打印
    public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
        double pageWidth = UnitUtils.inch2pt(this.getPaperWidth());
        double pageHeight = UnitUtils.inch2pt(this.getPaperHeight());

        double hScale = pageFormat.getImageableWidth() / pageWidth / UnitUtils.PIXEL_PER_PT;
        double vScale = pageFormat.getImageableHeight() / pageHeight / UnitUtils.PIXEL_PER_PT;

        Graphics2D g2 = (Graphics2D) g;

        double scale = Math.min(hScale, vScale);

        if (scale < 1.0D) {
            g2.scale(scale, scale);
        }

        this.printPaint(g2, false);

        return Printable.PAGE_EXISTS;
    }

    /**
     * 打印绘制
     * 
     * @param g2 绘制对象
     * @param drawBackground 是否绘制背景
     */
    public void printPaint(Graphics2D g2, boolean drawBackground) {
        double width = this.getPaperWidth() - this.getMarginLeft() - this.getMarginRight();

        // 绘制区域
        // Rectangle2D drawArea =
        // new Rectangle2D.Double(UnitUtils.inch2pixel(this.getMarginLeft()),
        // UnitUtils.inch2pixel(this.getMarginTop()),
        // UnitUtils.inch2pixel(width),
        // UnitUtils.inch2pixel(this.getPaperHeight()
        // - this.getMarginTop()
        // - this.getMarginBottom()));
        // g2.setClip(drawArea);
        // 绘制页脚页眉
        this.paintHF(g2, width);
        // 绘制内容
        this.paintContent(g2,
                          new Rectangle2D.Double(this.getMarginLeft(),
                                                 this.getMarginTop() + this.getHeaderHeight(),
                                                 width,
                                                 this.getPaperHeight()
                                                         - this.getMarginTop()
                                                         - this.getMarginBottom()
                                                         - this.getHeaderHeight()
                                                         - this.getFooterHeight()),
                          drawBackground);
        // g2.setClip(null);
    }

    /**
     * 绘制页眉页脚
     * 
     * @param g2
     * @param width
     */
    private void paintHF(Graphics2D g2, double width) {
        ReportHF header = this.reportSettings.getHeader();

        int pixelWidth = UnitUtils.inch2pixel(width);
        int pixelHeight;

        if (header != null) {
            pixelHeight = UnitUtils.inch2pixel(header.getHeight());
            header.paint(g2,
                         new Rectangle2D.Double(UnitUtils.inch2pixel(this.getMarginLeft()),
                                                UnitUtils.inch2pixel(this.getMarginTop()),
                                                pixelWidth,
                                                pixelHeight),
                         pixelWidth,
                         this.getCurrentPageNumber(),
                         this.getTotalPages(),
                         this.getGroupPageNumber(),
                         this.getGroupTotalPages());
        }

        ReportHF footer = this.reportSettings.getFooter();

        if (footer != null) {
            pixelHeight = UnitUtils.inch2pixel(footer.getHeight());
            footer.paint(g2,
                         new Rectangle2D.Double(UnitUtils.inch2pixel(this.getMarginLeft()),

                                                UnitUtils.inch2pixel(this.getPaperHeight() - this.getMarginBottom())
                                                        - pixelHeight,
                                                pixelWidth,
                                                pixelHeight),
                         pixelWidth,
                         this.getCurrentPageNumber(),
                         this.getTotalPages(),
                         this.getGroupPageNumber(),
                         this.getGroupTotalPages());
        }
    }

    /**
     * 绘制内容
     * 
     * @param g2 图形对象
     * @param rect 绘制区域
     * @param drawBackground 是否绘制背景
     */
    private void paintContent(Graphics2D g2, Rectangle2D rect, boolean drawBackground) {
        int startX = UnitUtils.inch2pixel(rect.getX());
        int startY = UnitUtils.inch2pixel(rect.getY());
        int height = UnitUtils.inch2pixel(rect.getHeight());

        g2.translate(startX, startY);
        this.paintCells(g2, height);
        g2.translate(-startX, -startY);
    }

    // /**
    // * 子报表
    // *
    // * @param row 所在行
    // * @return 如果所在行包括子报表的子报表
    // */
    // private ReportModel getsRowSubReport(int row) {
    // for (int i = 0, count = this.reportModel.getColumnCount(); i < count; i++) {
    // Cell cell = this.reportModel.getCell(i, row);
    // Object value = cell.getValue();
    // if ((value != null) && (value instanceof ReportModel)) {
    // return (ReportModel) value;
    // }
    //
    // }
    // return null;
    // }

    /**
     * 绘制所有单元格
     * 
     * @param g2 表格单元格区域
     * @param clientHeight 客户端高度
     */
    public void paintCells(Graphics2D g2, int clientHeight) {
        int fromRow = this.rowFT.from.getRow();
        int toRow = this.rowFT.to.getRow();
        // int fromRowSub = this.rowFT.from.getSubRow();
        // int toRowSub = this.rowFT.to.getSubRow();

        int rowHeight = toRow - fromRow;

        // if (this.rowFT.to.getSubRow() != 0) {// 有子行，则包含
        // rowHeight += 1;
        // }

        Rectangle rect =
                new Rectangle(this.columnFT.from,
                              this.rowFT.from.getRow(),
                              this.columnFT.to - this.columnFT.from,
                              rowHeight);
        int maxColumn = rect.x + rect.width;

        final Iterator<Cell> cellIterator = this.reportModel.intersect(rect.x, rect.y, rect.width, rect.height);

        ColumnPropList cwL = this.reportModel.getColumnPropList();
        RowPropList rhL = this.reportModel.getRowPropList();
        List<Integer> fixedHeaders = this.reportModel.getFixedHeaderColumns();

        // 计算开始X
        int fixedWidth = 0;
        List<Integer> fixedHeaderColumnsNotInCurrPage = new ArrayList<Integer>();
        for (int index : fixedHeaders) {
            // 不包含
            if ((index < this.columnFT.from) || (index > this.columnFT.to)) {
                fixedWidth += cwL.getWidth(index);
                fixedHeaderColumnsNotInCurrPage.add(index);
            }
        }

        // // 处理列尾部
        // List<Integer> fixedfooterColumnsNotInCurrPage = new ArrayList<Integer>();
        // for (int index : this.reportModel.getFixedFooterColumns()) {
        // if ((index < this.columnFT.from) || (index > this.columnFT.to)) {
        // fixedfooterColumnsNotInCurrPage.add(index);
        // }
        // }

        // 计算开始Y
        int fixedHeight = 0;
        List<Integer> fixedHeaderRowsNotInCurrPage = new ArrayList<Integer>();
        for (int index : this.reportModel.getFixedHeaderRows()) {
            if ((index < this.rowFT.from.getRow()) || (index > this.rowFT.to.getRow())) {
                fixedHeight += rhL.getHeight(index);
            }
            fixedHeaderRowsNotInCurrPage.add(index);
        }

        // // 处理行尾部
        // List<Integer> fixedfooterRowsNotInCurrPage = new ArrayList<Integer>();
        // for (int index : this.reportModel.getFixedFooterRows()) {
        // if ((index < this.rowFT.from.getRow()) || (index > this.rowFT.to.getRow())) {
        // fixedfooterRowsNotInCurrPage.add(index);
        // }
        // }

        // 绘制固定列首
        int fx = 0;
        for (int fixedIndex : fixedHeaderColumnsNotInCurrPage) {
            if (!fixedHeaderRowsNotInCurrPage.isEmpty()) {
                int hc = 0;
                for (int row : fixedHeaderRowsNotInCurrPage) {
                    if (row == 0 || row == 1) {
                        int y = hc;
                        hc += rhL.getHeight(row);

                        // 特殊处理
                        if (fixedIndex == 0) {
                            Cell cell = this.reportModel.getCell(fixedIndex, row);

                            int w = 0;
                            for (int c : fixedHeaderColumnsNotInCurrPage) {
                                w += this.reportModel.getColumnWidth(c);
                            }

                            for (int c = this.columnFT.from, to = this.columnFT.to; c < to; c++) {
                                w += this.reportModel.getColumnWidth(c);
                            }

                            int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
                            Rectangle cellRect = new Rectangle(fx, y, w, h);

                            PaintUtils.paintCellElement(g2, cell, cellRect);
                        }
                        continue;
                    } else {
                        Cell cell = this.reportModel.getCell(fixedIndex, row);

                        int y = hc;
                        hc += rhL.getHeight(row);
                        int w =
                                cwL.getRangeValue(cell.getColumn(),
                                                  Math.min(maxColumn - this.columnFT.from,
                                                           cell.getColumn() + cell.getColumnSpan()));

                        int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
                        Rectangle cellRect = new Rectangle(fx, y, w, h);

                        PaintUtils.paintCellElement(g2, cell, cellRect);
                    }
                }
            }
            for (int i = this.rowFT.from.getRow(), to = this.rowFT.to.getRow(); i < to; i++) {
                if (i == 0 || i == 1) {
                    // 特殊处理
                    // if (fixedIndex == 0) {
                    // Cell cell = this.reportModel.getCell(fixedIndex, i);
                    //
                    // int y = fixedHeight + rhL.getRangeValue(rect.y, cell.getRow());
                    // int w =
                    // cwL.getRangeValue(cell.getColumn(),
                    // Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
                    // int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
                    // Rectangle cellRect = new Rectangle(fx, y, w, h);
                    //
                    // PaintUtils.paintCellElement(g2, cell, cellRect);
                    // }
                    continue;
                }

                Cell cell = this.reportModel.getCell(fixedIndex, i);

                int y = fixedHeight + rhL.getRangeValue(rect.y, cell.getRow());
                int w =
                        cwL.getRangeValue(cell.getColumn(),
                                          Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
                int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
                Rectangle cellRect = new Rectangle(fx, y, w, h);

                PaintUtils.paintCellElement(g2, cell, cellRect);
            }

            fx += cwL.getWidth(fixedIndex);
        }

        // // 绘制固定列尾
        // fx = fixedWidth + cwL.getRangeValue(this.columnFT.from, this.columnFT.to);
        // for (int fixedIndex : fixedfooterColumnsNotInCurrPage) {
        // if (!fixedHeaderRowsNotInCurrPage.isEmpty()) {
        // int hc = 0;
        // for (int row : fixedHeaderRowsNotInCurrPage) {
        // Cell cell = this.reportModel.getCell(fixedIndex, row);
        //
        // int y = hc;
        // hc += rhL.getHeight(row);
        // int w =
        // cwL.getRangeValue(cell.getColumn(),
        // Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
        // int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
        // Rectangle cellRect = new Rectangle(fx, y, w, h);
        //
        // PaintUtils.paintCellElement(g2, cell, cellRect);
        // }
        // }
        //
        // for (int i = this.rowFT.from.getRow(), to = this.rowFT.to.getRow(); i < to; i++) {
        // Cell cell = this.reportModel.getCell(fixedIndex, i);
        //
        // int y = fixedHeight + rhL.getRangeValue(rect.y, cell.getRow());
        // int w =
        // cwL.getRangeValue(cell.getColumn(),
        // Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
        // int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
        // Rectangle cellRect = new Rectangle(fx, y, w, h);
        //
        // PaintUtils.paintCellElement(g2, cell, cellRect);
        // }
        //
        // if (!fixedfooterRowsNotInCurrPage.isEmpty()) {
        // int hc = fixedHeight + rhL.getRangeValue(this.rowFT.from.getRow(), this.rowFT.to.getRow());
        // for (int row : fixedfooterRowsNotInCurrPage) {
        // Cell cell = this.reportModel.getCell(fixedIndex, row);
        //
        // int y = hc;
        // hc += rhL.getHeight(row);
        // int w =
        // cwL.getRangeValue(cell.getColumn(),
        // Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
        // int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
        // Rectangle cellRect = new Rectangle(fx, y, w, h);
        //
        // PaintUtils.paintCellElement(g2, cell, cellRect);
        // }
        // }
        // fx += cwL.getWidth(fixedIndex);
        // }

        // 绘制固定行首
        int fy = 0;
        for (int fixedIndex : fixedHeaderRowsNotInCurrPage) {
            for (int i = this.columnFT.from, to = this.columnFT.to; i < to; i++) {
                if (!fixedHeaders.contains(i) && this.reportModel.getColumnType(i) == ColumnType.HEADER) {
                    continue;
                }

                Cell cell = this.reportModel.getCell(i, fixedIndex);
                if (i == this.columnFT.from) {
                    // 第一列可能是合并列
                    if (i != 0 && cell == Cell.EMPTY_CELL) {
                        // 查找到它的和并列并处理
                        Cell mc = this.getMergedCell(i, fixedIndex);
                        if (mc == Cell.EMPTY_CELL) {
                            continue;
                        }

                        int w = cwL.getRangeValue(i, Math.min(maxColumn, mc.getColumn() + mc.getColumnSpan()));
                        if (w < 0) {
                            continue;
                        }
                        int x = fixedWidth + cwL.getRangeValue(rect.x, i);
                        int h = rhL.getRangeValue(fixedIndex, fixedIndex + mc.getRowSpan());
                        Rectangle cellRect = new Rectangle(x, fy, w, h);
                        PaintUtils.paintCellElement(g2, mc, cellRect);
                    } else {

                        int x = fixedWidth + cwL.getRangeValue(rect.x, cell.getColumn());
                        int w =
                                cwL.getRangeValue(cell.getColumn(),
                                                  Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
                        int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
                        Rectangle cellRect = new Rectangle(x, fy, w, h);

                        PaintUtils.paintCellElement(g2, cell, cellRect);
                    }
                } else {
                    int x = fixedWidth + cwL.getRangeValue(rect.x, cell.getColumn());
                    int w =
                            cwL.getRangeValue(cell.getColumn(),
                                              Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
                    int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
                    Rectangle cellRect = new Rectangle(x, fy, w, h);

                    PaintUtils.paintCellElement(g2, cell, cellRect);
                }
            }

            fy += rhL.getHeight(fixedIndex);
        }

        // // 绘制固定行尾
        // fy = fixedHeight + rhL.getRangeValue(this.rowFT.from.getRow(), this.rowFT.to.getRow());
        // for (int fixedIndex : fixedfooterRowsNotInCurrPage) {
        // for (int i = this.columnFT.from, to = this.columnFT.to; i < to; i++) {
        // Cell cell = this.reportModel.getCell(i, fixedIndex);
        //
        // int x = fixedWidth + cwL.getRangeValue(rect.x, cell.getColumn());
        // int w =
        // cwL.getRangeValue(cell.getColumn(),
        // Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
        // int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());
        // Rectangle cellRect = new Rectangle(x, fy, w, h);
        //
        // PaintUtils.paintCellElement(g2, cell, cellRect);
        // }
        //
        // fy += rhL.getHeight(fixedIndex);
        // }

        // 有抬头换行
        int hhh1 = 0;
        int yyy1 = rect.y;
        // if (fromRowSub != 0) {
        // ReportModel rmodel = getsRowSubReport(yyy1);
        // hhh1 = rmodel.getRowPropList().getRangeValueFromZero(fromRowSub);
        // }

        // int hhh2 = 0;
        // int yyy2 = rect.y + rect.height - 1;
        // // 有尾部换行
        // if (toRowSub != 0) {
        // // 高度为<toRowSub的行
        // ReportModel rmodel = getsRowSubReport(yyy2);
        // hhh2 = rmodel.getRowPropList().getRangeValueFromZero(toRowSub);
        // }

        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            if (fixedHeaderRowsNotInCurrPage.contains(cell.getRow())) {
                continue;
            }
            int x = fixedWidth + cwL.getRangeValue(rect.x, cell.getColumn());
            int y = fixedHeight + rhL.getRangeValue(rect.y, cell.getRow()) - hhh1;
            int w = cwL.getRangeValue(cell.getColumn(), Math.min(maxColumn, cell.getColumn() + cell.getColumnSpan()));
            int h = rhL.getRangeValue(cell.getRow(), cell.getRow() + cell.getRowSpan());

            // 如果是第一行
            // if ((cell.getRow() == yyy1) && (fromRowSub != 0)) {
            if (cell.getRow() == yyy1) {
                h = h - hhh1;
                y = fixedHeight;
                Rectangle cellRect = new Rectangle(x, y, w, h);
                PaintUtils.paintCellElement(g2, cell, cellRect, -hhh1);
                // } else if (cell.getRow() == yyy2) {
                // h = Math.min(hhh2, h);
                //
                // Rectangle cellRect = new Rectangle(x, y, w, h);
                // PaintUtils.paintCellElement(g2, cell, cellRect);
            } else {
                Rectangle cellRect = new Rectangle(x, y, w, h);
                PaintUtils.paintCellElement(g2, cell, cellRect);
            }
        }
    }

    /**
     * 查找对应的合并单元格
     * 
     * @param column 列
     * @param row 行
     * @return 合并单元格
     */
    private Cell getMergedCell(int column, int row) {
        for (int i = column - 1; i >= 0; i--) {
            Cell cell = this.reportModel.getCell(i, row);

            if (cell.isMerged()) {
                if (this.reportModel.getColumnType(i) == ColumnType.HEADER) {
                    return Cell.EMPTY_CELL;
                }

                return cell;
            }
        }

        return Cell.EMPTY_CELL;
    }

    /**
     * 获取当前页码
     * 
     * @return 当前页码
     */
    public int getCurrentPageNumber() {
        return this.currentPageNumber;
    }

    /**
     * 设置当前页码
     * 
     * @param currentPageNumber 页码
     */
    public void setCurrentPageNumber(int currentPageNumber) {
        this.currentPageNumber = currentPageNumber;
    }

    /**
     * 
     * @return 总页数
     */
    public int getTotalPages() {
        return this.totalPages;
    }

    /**
     * 设置总页数
     * 
     * @param totalPages 总页数
     */
    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }

    /**
     * 分组页码
     * 
     * @param groupPageNumber 分组页码
     */
    public void setGroupPageNumber(int groupPageNumber) {
        this.groupPageNumber = groupPageNumber;
    }

    /**
     * 获取分组页码
     * 
     * @return 分组页码
     */
    public int getGroupPageNumber() {
        return groupPageNumber;
    }

    /**
     * 分组总页数
     * 
     * @param groupTotalPages 分组总页数
     */
    public void setGroupTotalPages(int groupTotalPages) {
        this.groupTotalPages = groupTotalPages;
    }

    /**
     * 分组总页数
     * 
     * @return 分组总页数
     */
    public int getGroupTotalPages() {
        return groupTotalPages;
    }

    public FT getColumnFT() {
        return columnFT;
    }

    // 获取行分页
    public RowFT getRowFT() {
        return rowFT;
    }

    /**
     * 获取当前模型
     * 
     * @return 当前模型
     */
    public ReportModel getReportModel() {
        return this.reportModel;
    }
}
